uboot 2021.10源码分析(启动流程)

您所在的位置:网站首页 u-boot fdt uboot 2021.10源码分析(启动流程)

uboot 2021.10源码分析(启动流程)

#uboot 2021.10源码分析(启动流程)| 来源: 网络整理| 查看: 265

uboot版本:2021.10

平台:armv8  rk3399  eMMC 16G  LPDDR4 4G

本文主要基于uboot的执行流程进行分析而忽略了相关细节,从uboot的基本框架结构着手,新的uboot框架是有三部分组成的:TPL SPL uboot,而且编译后产生的镜像也是有三部分构成,所以也可以认为是三个独立的程序,只不过合在了一个代码框架里面了。

1. 编译过程

编译过程主要是通过CONFIG_TPL_BUILD CONFIG_SPL_BUILD这两个宏来指定,三个阶段开关打开情况:

TPL

CONFIG_TPL_BUILD=EN 

CONFIG_SPL_BUILD=EN

SPL

CONFIG_TPL_BUILD=DIS 

CONFIG_SPL_BUILD=EN

uboot

CONFIG_TPL_BUILD=DIS 

CONFIG_SPL_BUILD=DIS

新版本在编译完成之后会在源码目录下生成tpl和spl文件夹,这两个文件夹就是用来保存编译后的object文件

 可以看出整个uboot是由三部分固件组成:u-boot-tpl.bin u-boot-spl.bin u-boot.bin

DeviceTree文件说明

每一个bin文件其实都包含了对应的dtb文件,dts/dt.dtb是uboot阶段使用的完整的dtb文件,而实际上u-boot-tpl.dtb和u-boot-spl.dtb是同一个文件,都是缩小版的dtb,在doc/README.tpl中有说明:

work@ubuntu:~/uboot/u-boot-2021.10$ grep "u-boot-tpl.dtb" -r ./ ./tpl/.u-boot-tpl.dtb.cmd:cmd_tpl/u-boot-tpl.dtb := cp tpl/dts/dt-tpl.dtb tpl/u-boot-tpl.dtb ./tpl/.u-boot-tpl.bin.cmd:cmd_tpl/u-boot-tpl.bin := cp tpl/u-boot-tpl-dtb.bin tpl/u-boot-tpl.bin ./tpl/.u-boot-tpl-dtb.bin.cmd:cmd_tpl/u-boot-tpl-dtb.bin := cat tpl/u-boot-tpl-nodtb.bin tpl/u-boot-tpl.dtb > tpl/u-boot-tpl-dtb.bin work@ubuntu:~/uboot/u-boot-2021.10$ grep "dt-tpl.dtb" -r ./ ./tpl/.u-boot-tpl.dtb.cmd:cmd_tpl/u-boot-tpl.dtb := cp tpl/dts/dt-tpl.dtb tpl/u-boot-tpl.dtb ./tpl/dts/.dt-tpl.dtb.cmd:cmd_tpl/dts/dt-tpl.dtb := ./tools/fdtgrep -b u-boot,dm-pre-reloc -b u-boot,dm-tpl -RT dts/dt.dtb -n /chosen -n /config -O dtb | ./tools/fdtgrep -r -O dtb - -o tpl/dts/dt-tpl.dtb -P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl -P pinctrl-0 -P pinctrl-names -P clock-names -P interrupt-parent -P assigned-clocks -P assigned-clock-rates -P assigned-clock-parents

通过查找发现u-boot-tpl.dtb的生成是通过./tools/fdtgrep来实现的,这个工具的作用是从dt.dtb文件中把需要的devicetree提取出来。

这样做的原因是因为cpu刚启动的时候ddr还没有被初始化,tpl阶段要在cpu内部的sram中执行,所以要尽量的小一些,刚开始只要进行一些必须的初始化就可以了。

我在分析源码流程的时候主要是通过这三个固件源码部分来分析的

2. TPL阶段 start.s //第一个执行的文件 reset: save_boot_params() bootrom.c setjmp(brom_ctx) ret 0 //这里用于跳转到SPL阶段 save_boot_params_ret: reset lowlevel_init: //底层初始化 关Cache/BPB/TLB等 _main() crt0_64.s board_init_f()//forward 前级舒适化 arch/tpl.c board_init_r()//rear 后级初始化

 上电第一个执行的文件是start.s,然后主要是board_init_f()和board_init_r()这两个函数

初始化过程 board_init_f() board_init_f() arch/tpl.c spl_early_init()//早期初始化 在common/spl/spl.c文件中 跟SPL阶段共用 spl_common_init() dm_init_and_scan() dm_scan() dm_extended_scan() dm_scan_fdt() dm_scan_fdt_node() //若status=disable则不执行lists_bind_fdt() ofnode_is_enabled() fdtdec_get_is_enabled() fdt_getprop() fdt_getprop_namelen() fdt_get_property_namelen_() lists_bind_fdt() driver_check_compatible() device_bind_with_driver_data() device_bind_common() uclass_get() drv->bind(dev)->rk3399_syscon() ...

这里主要是在device_bind_common()中进行相应设备的驱动程序绑定,TPL阶段在编译的时候使用的devicetree是u-boot-tpl.dtb,dm_scan_fdt()这个函数相当于搜索dts中的设备并是否是okay状态,是的话就为其挂载驱动并初始化。

这个时候只绑定了CPU相关的基础驱动 因为MMC等这些驱动是在spl.bin里面,这时候没有被加载,这时候驱动的地址是在0xff8xxxxx 以上,运行在cpu的SRAM中,只加载了tpl.bin 里面没有emmc等设备驱动。

将lists_bin_fdt的调试信息打开:

[TPL阶段] U-Boot TPL 2021.10 (Dec 06 2021 - 18:14:33) lists_bind_fdt - found match at 'ns16550_serial': 'ns16550' matches 'snps,dw-apb-uart' devname 'serial@ff1a0000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmu' devname 'power-management@ff310000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmugrf' devname 'syscon@ff320000' lists_bind_fdt - found match at 'rockchip_rk3399_pmucru': 'rockchip,rk3399-pmucru' matches 'rockchip,rk3399-pmucru' devname 'pmu-clock-controller@ff750000' lists_bind_fdt - found match at 'rockchip_rk3399_cru': 'rockchip,rk3399-cru' matches 'rockchip,rk3399-cru' devname 'clock-controller@ff760000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-grf' devname 'syscon@ff770000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-cic' devname 'syscon@ff620000' lists_bind_fdt - found match at 'rockchip_rk3399_dmc': 'rockchip,rk3399-dmc' matches 'rockchip,rk3399-dmc' devname 'dmc' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmusgrf' devname 'syscon@ff330000' Channel 0: LPDDR4, 50MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB Channel 1: LPDDR4, 50MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB 256B stride lpddr4_set_rate: change freq to 400000000 mhz 0, 1 lpddr4_set_rate: change freq to 800000000 mhz 1, 0 Trying to boot from BOOTROM Returning to boot ROM... [SPL阶段] lists_bind_fdt - found match at 'rockchip_rk3288_dw_mshc': 'rockchip,rk2928-dw-mshc' matches 'rockchip,rk3288-dw-mshc' devname 'mmc@fe320000' lists_bind_fdt - found match at 'rockchip_sdhci_5_1': 'arasan,sdhci-5.1' matches 'arasan,sdhci-5.1' devname 'mmc@fe330000' lists_bind_fdt - found match at 'ns16550_serial': 'ns16550' matches 'snps,dw-apb-uart' devname 'serial@ff1a0000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmu' devname 'power-management@ff310000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmugrf' devname 'syscon@ff320000' lists_bind_fdt - found match at 'rockchip_rk3399_pmucru': 'rockchip,rk3399-pmucru' matches 'rockchip,rk3399-pmucru' devname 'pmu-clock-controller@ff750000' lists_bind_fdt - found match at 'rockchip_rk3399_cru': 'rockchip,rk3399-cru' matches 'rockchip,rk3399-cru' devname 'clock-controller@ff760000' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-grf' devname 'syscon@ff770000' lists_bind_fdt - found match at 'rockchip_rk3399_pinctrl': 'rockchip,rk3399-pinctrl' matches 'rockchip,rk3399-pinctrl' devname 'pinctrl' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-cic' devname 'syscon@ff620000' lists_bind_fdt - found match at 'rockchip_rk3399_dmc': 'rockchip,rk3399-dmc' matches 'rockchip,rk3399-dmc' devname 'dmc' lists_bind_fdt - found match at 'rk3399_syscon': 'rockchip,rk3399-grf' matches 'rockchip,rk3399-pmusgrf' devname 'syscon@ff330000' U-Boot SPL 2021.10 (Dec 06 2021 - 18:14:33 -0800) Trying to boot from MMC2

可以发现在TPL阶段并没有找到mmc@fe330000设备的驱动程序,因为这个阶段驱动并没有加载,这个阶段初始化的设备是serial,syscon,pmu,dmc这些基本必须设备。

引导过程 board_init_r() board_init_r() board_boot_order() //arch/../spl-boot-order.c fdt_path_offset() spl_node_to_boot_device() uclass_get_device_by_of_offset() uclass_find_device_by_of_offset() uclass_get_device_tail() device_probe() //若找到设备,则执行相应的probe boot_from_devices() loader->load_image()->spl_return_to_bootrom() board_return_to_bootrom() back_to_bootrom() _back_to_bootrom() longjmp(brom_ctx, brom_cmd); 跳转到SPL setjmp(brom_ctx)--save_boot_params() ret>0

因为在上一阶段中加载了一个BOOTROM设备的驱动程序,在这里执行相应的初始化程序(probe),如syscon, ddr等都在这个阶段进行初始化工作。

这里找到了一个SPL_LOAD_IMAGE_METHOD类型的引导设备BOOTROM ,对应的执行了spl_return_to_bootrom函数,在执行longjmp之后相当于又跳转到start.s中进行reset,然后进入SPL阶段。

3. SPL阶段 crt0_64.s board_init_f() board_init_r() 初始化过程 board_init_f() board_init_f() arch/spl.c spl_early_init() spl_common_init() dm_init_and_scan() dm_scan() dm_extended_scan() dm_scan_fdt() dm_scan_fdt() dm_scan_fdt_node() //若status=disable则不执行lists_bind_fdt() ofnode_is_enabled() fdtdec_get_is_enabled() fdt_getprop() fdt_getprop_namelen() fdt_get_property_namelen_() lists_bind_fdt()//这里比较dts中设备的名称和驱动的名称是否一致 driver_check_compatible() device_bind_with_driver_data() device_bind_common()//在这里完成设备驱动的绑定 uclass_get() drv->bind(dev)->rockchip_sdhci_bind() ... //这里以初始化eMMC为例 sdhci_bind() mmc_bind() mmc_bind() blk_create_devicef() blk_create_device() device_bind_driver() device_bind_driver_to_node() device_bind_with_driver_data() 引导过程 board_init_r() board_init_r() //common/spl.c board_boot_order() //arch/../spl-boot-order.c fdt_path_offset() spl_node_to_boot_device() uclass_get_device_by_of_offset() uclass_find_device_by_of_offset() uclass_get_device_tail() device_probe() //若找到设备,则执行相应的probe boot_from_devices() spl_ll_find_loader() spl_load_image() loader->load_image()->spl_mmc_load_image() spl_mmc_load() spl_mmc_find_device() mmc_init_device() mmc_start_init() mmc_get_op_cond() mmc_power_init() mmc_load_image_raw_sector() spl_load_simple_fit() spl_simple_fit_read() spl_fit_get_image_node("loadables") spl_load_fit_image() fit_image_get_load() fit_image_get_address()--spl_image->load_addr=0x200000 spl_fit_append_fdt() spl_load_fit_image() ->entry_point=load_addr jump_to_image_no_args(&spl_image) spl_image->entry_point() 跳转到uboot 4. uboot阶段 crt0_64.s board_init_f() relocate_code()//代码重映射 board_init_r() 初始化过程 board_init_f() board_init_f() board_f.c initcall_run_list()->init_sequence_f[]() //执行这个数组中的函数进行初始化 ... initf_dm() //初始化设备驱动 dm_init_and_scan() ... display_options() //打印起始信息如:U-Boot 2021.04 (Dec 03 2021 - 17:19:14 +0800) display_options_get_banner() display_options_get_banner_priv() 引导过程 board_init_r() board_init_r() board_r.c initcall_run_list()->init_sequence_r[]() //执行数组中的函数 run_main_loop() main_loop() bootdelay_process()//在环境变量env中获取bootcmd的值(本例为run distro_bootcmd) autoboot_command("run distro_bootcmd")//检测是否有ctl+c按下,若按下则退出,否则执行自动脚本不会退出 abortboot() run_command_list() cli_simple_run_command_list() cli_simple_run_command() cmd_process() cli_loop()//进入命令行,等待输入命令 parse_file_outer() parse_stream_outer() run_list() run_list_real() run_pipe_real() cmd_process() find_cmd() cmd_call() cmdtp->cmd_rep() -> do_mmcops()... do_mmcops() argc=3 argv[0]=mmc argv[1]=dev //以mmc命令为例 find_cmd_tbl() cp->cmd() do_mmc_dev() init_mmc_device() __init_mmc_device() mmc_init() mmc_start_init() mmc_get_op_cond() 自启动脚本的执行流程是: run distro_bootcmd(env distro_bootcmd)-> run bootcmd_${target}-> //target= mmc1 mmc0 usb0 pxe dhcp run bootcmd_mmc0(env bootcmd_mmc0)...-> run mmc_boot(env mmc_boot)-> run scan_dev_for_boot_part(env scan_dev_for_boot_part) fstype() -> run scan_dev_for_boot(env scan_dev_for_boot)-> run scan_dev_for_extlinux(env scan_dev_for_extlinux)...-> run boot_extlinux(env boot_extlinux)-> sysboot()

下面是我使用的开发板的环境变量

altbootcmd=setenv boot_syslinux_conf extlinux/extlinux-rollback.conf;run distro_bootcmd arch=arm baudrate=1500000 board=evb_rk3399 board_name=evb_rk3399 boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr} boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootaa64.efi; if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi boot_efi_bootmgr=if fdt addr ${fdt_addr_r}; then bootefi bootmgr ${fdt_addr_r};else bootefi bootmgr;fi boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf} boot_net_usb_start=usb start boot_prefixes=/ /boot/ boot_script_dhcp=boot.scr.uimg boot_scripts=boot.scr.uimg boot.scr boot_syslinux_conf=extlinux/extlinux.conf boot_targets=mmc1 mmc0 usb0 pxe dhcp sf0 bootcmd=run distro_bootcmd bootcmd_dhcp=devtype=dhcp; run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00011:UNDI:003000;setenv bootp_arch 0xb;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci; bootcmd_mmc0=devnum=0; run mmc_boot bootcmd_mmc1=devnum=1; run mmc_boot bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi bootcmd_sf0=busnum=0; run sf_boot bootcmd_usb0=devnum=0; run usb_boot bootdelay=2 cpu=armv8 distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done efi_dtb_prefixes=/ /dtb/ /dtb/current/ ethact=ethernet@fe300000 fdt_addr_r=0x01f00000 fdtcontroladdr=f5f28700 fdtfile=rockchip/rk3399-khadas-edge.dtb fdtoverlay_addr_r=0x02000000 kernel_addr_r=0x02080000 kernel_comp_addr_r=0x08000000 kernel_comp_size=0x2000000 load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile} mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi partitions=uuid_disk=${uuid_gpt_disk};name=loader1,start=32K,size=4000K,uuid=${uuid_gpt_loader1};name=loader2,start=8MB,size=4MB,uuid=${uuid_gpt_loader2};name=trust,size=4M,uuid=${uuid_gpt_atf};name=boot,size=112M,bootable,uuid=${uuid_gpt_boot};name=rootfs,size=-,uuid=B921B045-1DF0-41C3-AF44-4C6F280D3FAE; pxefile_addr_r=0x00600000 ramdisk_addr_r=0x06000000 scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi; scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done; setenv devplist scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;run boot_efi_bootmgr;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootaa64.efi; then echo Found EFI removable media binary efi/boot/bootaa64.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then echo Found ${prefix}${boot_syslinux_conf}; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done scan_sf_for_scripts=${devtype} read ${scriptaddr} ${script_offset_f} ${script_size_f}; source ${scriptaddr}; echo SCRIPT FAILED: continuing... script_offset_f=0xffe000 script_size_f=0x2000 scriptaddr=0x00500000 sf_boot=if sf probe ${busnum}; then devtype=sf; run scan_sf_for_scripts; fi soc=rk3399 stderr=serial@ff1a0000 stdin=serial@ff1a0000 stdout=serial@ff1a0000 usb_boot=usb start; if usb dev ${devnum}; then devtype=usb; run scan_dev_for_boot_part; fi vendor=rockchip



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3